/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../macro/head.h"
#include "aio_helper.h"
#include "aio_tcp.h"
#include "head.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos_aio
{
    aio_tcp::aio_tcp( aio_impl* pAioImpl ) : m_pAioImpl( pAioImpl )
    {
    }

    aio_tcp::~aio_tcp()
    {
    }

    // 
    // m_bData[0] : true or false for result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_init( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        i_connect * lpUserKey = (i_connect *)lpMsg->get_void( 0, 0 );

        SOCKET hSocket = INVALID_SOCKET;
        xos::i_socket* lpSocket = 0;
        aio_key* lpAioKey = 0;

        if( 0 == nRet )
        {
            lpMsg->set_msg( 0, i_aio::AIO_TCP_INIT_RET );
            lpMsg->set_bool( 0, false );
            lpMsg->set_void( 1, 0 );
        }

        if( 0 == nRet )
        {
            lpSocket = mgr::container()->xos()->socket();
        }

        if( 0 == nRet )
        {
            uint16_t usPort = (uint16_t)lpMsg->get_int( 1, 0 );
            const char* pszIp = lpMsg->get_str( 1, 0, 0, 0 );
            nRet = lpSocket->tcp_init( pszIp, usPort, true );
        }

        if( 0 == nRet )
        {
            lpSocket->set_async( true );
        }

        if( 0 == nRet )
        {
            lpSocket->tcp_listen( 5 );
        }

        if( 0 == nRet )
        {
            uint16_t usPort = 0;
            char szIp[100] = { 0 };
            nRet = lpSocket->get_local_addr( szIp, &usPort );
            if( 0 == nRet )
            {
                lpMsg->set_str( 1, szIp );
                lpMsg->set_int( 1, usPort );
            }
        }

        if( 0 == nRet )
        {
            lpAioKey = aio_key::get_item_from_pool();
            lpAioKey->init();
            lpAioKey->m_eState = aio_key::KEY_STATE_RUNNING;
            lpAioKey->m_lpUserKey = lpUserKey;
            lpAioKey->m_pSocket = lpSocket;
            hSocket = (SOCKET)lpSocket->get_socket();
        }

        if( 0 == nRet )
        {
            HANDLE h = CreateIoCompletionPort( (HANDLE)hSocket, m_pAioImpl->m_hIocp, (ULONG_PTR)lpAioKey, 0 );
            if( h != m_pAioImpl->m_hIocp )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            post_enough_accept( lpAioKey );
        }

        if( 0 == nRet )
        {
            lpMsg->set_void( 1, lpAioKey );
            lpMsg->set_bool( 0, true );
            lpSocket = 0;
            lpAioKey = 0;
        }

        m_pAioImpl->notify( lpMsg );
        lpMsg = 0;

        if( lpSocket )
        {
            lpSocket->release();
            lpSocket = 0;
        }

        if( lpAioKey )
        {
            lpAioKey->m_pSocket = 0;
            lpAioKey->release();
            lpAioKey = 0;
        }

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_accept_ret( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;

        aio_key * lpClientKey = (aio_key *)lpMsg->get_void( 2, 0 );
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );

        xos::i_socket* pClientSocket = lpClientKey->m_pSocket;
        xos::i_socket* lpSocket = lpAioKey->m_pSocket;

        xos_box::i_buf* lpBuf = lpMsg->get_buf( 0, 0 );

        --lpAioKey->m_nPostAcceptNum;
        lpMsg->set_buf( 0, 0 );

        if( (0 != nResult) || !lpMsg->get_bool( 0, 0 ) )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            sockaddr_storage * local = 0, * remote = 0;
            {
                char * lpszBuf = lpBuf->get_data( 0, 0, 0, 0 );
                DWORD dwS = sizeof( sockaddr_storage );
                DWORD dwSize = dwS + 16;
                int l_size = dwS;
                int r_size = dwS;
                m_pAioImpl->m_lpGetAcceptExSockaddrs( lpszBuf, 0, dwSize, dwSize, (LPSOCKADDR *)&local, &l_size, (LPSOCKADDR *)&remote, &r_size );
            }
            unsigned short uPort = 0;
            char ip[100] = { 0 };
            {
                lpSocket->get_ip_port( *local, ip, &uPort );
                lpMsg->set_str( 1, ip );
                lpMsg->set_int( 1, uPort );
            }
            {
                lpSocket->get_ip_port( *remote, ip, &uPort );
                lpMsg->set_str( 2, ip );
                lpMsg->set_int( 2, uPort );
            }
        }

        if( 0 == nRet )
        {
            SOCKET hSocket = (SOCKET)lpSocket->get_socket();
            setsockopt( (SOCKET)pClientSocket->get_socket(),
                SOL_SOCKET,
                SO_UPDATE_CONNECT_CONTEXT,
                (char*)&hSocket,
                sizeof( hSocket ) );
        }

        if( 0 == nRet )
        {
            SOCKET hSocket = (SOCKET)pClientSocket->get_socket();
            if( m_pAioImpl->m_hIocp != CreateIoCompletionPort( (HANDLE)hSocket, m_pAioImpl->m_hIocp, (ULONG_PTR)lpClientKey, 0 ) )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            i_connect * pUserKey = lpAioKey->m_lpUserKey->create_accept_connect();
            lpClientKey->m_lpUserKey = pUserKey;
        }

        if( 0 == nRet )
        {
            lpClientKey->m_eState = aio_key::KEY_STATE_RUNNING;
            post_enough_accept( lpAioKey );
            post_enough_recv( lpClientKey );
        }

        if( 0 == nRet )
        {
            lpMsg->set_void( 0, lpClientKey->m_lpUserKey );
            lpMsg->set_void( 1, lpClientKey );
            lpMsg->set_bool( 0, true );
            m_pAioImpl->notify( lpMsg );
            lpClientKey = 0;
        }

        if( lpClientKey )
        {
            lpClientKey->release();
            lpClientKey = 0;
        }

        if( lpBuf )
        {
            lpBuf->release();
            lpBuf = 0;
        }

        xos_stl::release_interface( lpMsg );

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_accept( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;

        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos::i_socket* lpServerSocket = lpAioKey->m_pSocket;
        xos::i_socket* lpClientSocket = 0;

        aio_data* lpRetData = 0;
        xos_box::i_buf* lpBuf = 0;
        aio_key* pKey = 0;

        if( 0 == nRet )
        {
            lpMsg->set_msg( 0, i_aio::AIO_TCP_ACCPET_RET );
            lpMsg->set_bool( 0, false );
            lpMsg->set_void( 2, 0 );
            lpMsg->set_buf( 0, 0 );
            lpAioKey->m_nPostAcceptNum++;
        }

        if( 0 == nRet )
        {
            lpBuf = mgr::container()->box()->buf();
            lpMsg->set_buf( 0, lpBuf );
        }

        if( 0 == nRet )
        {
            lpRetData = aio_data::get_item_from_pool();
            lpRetData->init();
            lpRetData->m_nType = lpMsg->get_msg( 0, 0 );
            lpRetData->m_lpMsgData = lpMsg;
        }

        if( 0 == nRet )
        {
            lpClientSocket = mgr::container()->xos()->socket();
            nRet = lpClientSocket->tcp_init( 0, 0, false );
            if( 0 == nRet )
            {
                nRet = lpClientSocket->set_async( true );
            }
        }

        if( 0 == nRet )
        {
            pKey = aio_key::get_item_from_pool();
            pKey->init();
            pKey->m_pSocket = lpClientSocket;
            lpMsg->set_void( 2, pKey );
        }

        if( 0 == nRet )
        {
            SOCKET hClientSocket = (SOCKET)lpClientSocket->get_socket();
            SOCKET hSocket = (SOCKET)lpServerSocket->get_socket();
            DWORD dwSize = sizeof( sockaddr_storage ) + 16;
            lpMsg->set_bool( 0, true );
            if( !m_pAioImpl->m_lpAcceptEx( hSocket, hClientSocket, lpBuf->get_data( 0, 0, 0, 0 ), 0, dwSize, dwSize, &lpRetData->m_dwBytes, (WSAOVERLAPPED*)&lpRetData->m_ov_ex ) )
            {
                DWORD dwError = WSAGetLastError();
                if( ERROR_IO_PENDING != dwError )
                {
                    nRet = 1;
                }
            }
        }

        if( 0 != nRet )
        {
            lpMsg->set_bool( 0, false );
            PostQueuedCompletionStatus( m_pAioImpl->m_hIocp, 0, 0, (WSAOVERLAPPED*)&lpRetData->m_ov_ex );
        }

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_connect_ret( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos::i_socket* lpSocket = lpAioKey->m_pSocket;

        if( (0 != nResult) || !lpMsg->get_bool( 0, 0 ) )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            uint16_t usPort = 0;
            char szIp[100] = { 0 };
            nRet = lpSocket->get_local_addr( szIp, &usPort );
            if( 0 == nRet )
            {
                lpMsg->set_str( 1, szIp );
                lpMsg->set_int( 1, usPort );
            }
        }

        if( 0 == nRet )
        {
            lpAioKey->m_eState = aio_key::KEY_STATE_RUNNING;
            post_enough_recv( lpAioKey );
        }

        if( 0 == nRet )
        {
            lpMsg->set_bool( 0, true );
            lpAioKey = 0;
        }
        else
        {
            lpMsg->set_bool( 0, false );
            lpMsg->set_void( 1, 0 );
        }

        if( lpAioKey )
        {
            lpAioKey->release();
            lpAioKey = 0;
        }

        m_pAioImpl->notify( lpMsg );

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_connect( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        i_connect * lpUserKey = (i_connect *)lpMsg->get_void( 0, 0 );
        SOCKET hSocket = INVALID_SOCKET;
        xos::i_socket * lpSocket = 0;
        aio_data* lpRetData = 0;
        aio_key * lpAioKey = 0;

        lpMsg->set_msg( 0, i_aio::AIO_TCP_CONNECT_RET );
        lpMsg->set_bool( 0, false );

        if( 0 == nRet )
        {
            lpRetData = aio_data::get_item_from_pool();
            lpRetData->init();
            lpRetData->m_nType = lpMsg->get_msg( 0, 0 );
            lpRetData->m_lpMsgData = lpMsg;
        }

        if( 0 == nRet )
        {
            lpSocket = mgr::container()->xos()->socket();
            lpAioKey = aio_key::get_item_from_pool();
            lpAioKey->init();
            lpAioKey->m_lpUserKey = lpUserKey;
            lpAioKey->m_pSocket = lpSocket;
            lpMsg->set_void( 1, lpAioKey );
        }

        if( 0 == nRet )
        {
            uint16_t usPort = (uint16_t)lpMsg->get_int( 2, 0 );
            const char * pszIp = lpMsg->get_str( 2, 0, 0, 0 );
            sockaddr_storage addr;
            lpSocket->get_ipv6_addr( addr, pszIp );
            lpSocket->fill_ipv6_port( addr, usPort );
            memcpy( &lpRetData->m_addr, &addr, sizeof( sockaddr_storage ) );
        }

        if( 0 == nRet )
        {
            uint16_t usPort = (uint16_t)lpMsg->get_int( 1, 0 );
            const char * pszIp = lpMsg->get_str( 1, 0, 0, 0 );
            nRet = lpSocket->tcp_init( pszIp, usPort, true );
            if( 0 == nRet )
            {
                nRet = lpSocket->set_async( true );
            }
        }

        if( 0 == nRet )
        {
            hSocket = (SOCKET)lpSocket->get_socket();
            HANDLE h = CreateIoCompletionPort( (HANDLE)hSocket, m_pAioImpl->m_hIocp, (ULONG_PTR)lpAioKey, 0 );
            if( h != m_pAioImpl->m_hIocp )
            {
                nRet = 1;
            }
        }

        if( 0 == nRet )
        {
            lpMsg->set_bool( 0, true );
            if( !m_pAioImpl->m_lpConnectEx( hSocket, (const sockaddr*)&lpRetData->m_addr, sizeof( sockaddr_storage ), NULL, 0, NULL, (WSAOVERLAPPED*)&lpRetData->m_ov_ex ) )
            {
                DWORD dwErr = WSAGetLastError();
                if( ERROR_IO_PENDING != dwErr )
                {
                    nRet = 1;
                }
            }
        }

        if( 0 != nRet )
        {
            lpMsg->set_bool( 0, false );
            PostQueuedCompletionStatus( m_pAioImpl->m_hIocp, 0, 0, (WSAOVERLAPPED*)&lpRetData->m_ov_ex );
        }

        lpRetData = 0;

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[0] : recv len
    // m_lpBuf[0] : recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_recv_ret( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        using namespace std;
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos_box::i_buf* lpBuf = lpMsg->get_buf( 0, 0 );

        --lpAioKey->m_nPostRecvNum;

        if( (0 != nResult) || (0 == dwBytes) || !lpMsg->get_bool( 0, 0 ) )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            lpMsg->set_bool( 0, true );
            lpMsg->set_int( 0, dwBytes );
            lpBuf->set_len( dwBytes );
        }
        else
        {
            lpMsg->set_bool( 0, false );
        }

        if( 0 == nRet )
        {
            post_enough_recv( lpAioKey );
        }

        m_pAioImpl->notify( lpMsg );

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[0] : recv len
    // m_lpBuf[0] : recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_recv( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos::i_socket* lpSocket = lpAioKey->m_pSocket;
        SOCKET hSocket = (SOCKET)lpSocket->get_socket();
        xos_box::i_buf* lpBuf = lpMsg->get_buf( 0, 0 );
        aio_data* lpRetData = 0;

        lpMsg->set_msg( 0, i_aio::AIO_TCP_RECV_RET );
        lpMsg->set_bool( 0, false );
        lpAioKey->m_nPostRecvNum++;

        if( 0 == nRet )
        {
            lpRetData = aio_data::get_item_from_pool();
            lpRetData->init();
            lpRetData->m_nType = lpMsg->get_msg( 0, 0 );
            lpRetData->m_lpMsgData = lpMsg;
        }

        if( 0 == nRet )
        {
            WSABUF* lpWsaBuf = lpBuf->get_wsa_buf( 0 );
            lpMsg->set_bool( 0, true );
            lpMsg->set_int( 0, 0 );
            int ret = ::WSARecv( hSocket, lpWsaBuf, 1, &lpRetData->m_dwBytes, &lpRetData->m_dwFlags, (WSAOVERLAPPED*)&lpRetData->m_ov_ex, 0 );
            if( SOCKET_ERROR == ret )
            {
                DWORD dwErr = WSAGetLastError();
                if( WSA_IO_PENDING != dwErr )
                {
                    nRet = 1;
                }
            }
        }

        if( 0 != nRet )
        {
            lpMsg->set_bool( 0, false );
            PostQueuedCompletionStatus( m_pAioImpl->m_hIocp, 0, 0, (WSAOVERLAPPED*)&lpRetData->m_ov_ex );
        }

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[0] : send bytes
    // m_lpBuf[0] : send buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::tcp_send_ret( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        using namespace std;
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );

        --lpAioKey->m_nPostSendNum;

        if( (0 != nResult) || (0 == dwBytes) || !lpMsg->get_bool( 0, 0 ) )
        {
            nRet = 1;
        }

        if( 0 == nRet )
        {
            lpMsg->set_bool( 0, true );
            lpMsg->set_int( 0, dwBytes );
        }
        else
        {
            lpMsg->set_bool( 0, false );
        }

        if( 0 == nRet )
        {
            post_enough_send( lpAioKey );
        }

        m_pAioImpl->notify( lpMsg );

        return nRet;
    }

    int aio_tcp::tcp_send( int nResult, DWORD dwBytes, aio_key * lpKey, aio_data * lpData )
    {
        int ret = 0;

        xos_box::i_msg * lpMsg = lpData->m_lpMsgData;
        aio_key * lpAioKey = (aio_key *)lpMsg->get_void( 1, 0 );

        {
            aio_data::T * pData = 0;
            xos_stl::init_pool_item( pData );
            pData->m_lpMsgData = lpMsg;
            lpAioKey->m_pend_send_list.push_back( pData );
        }
        {
            post_enough_send( lpAioKey );
        }

        return ret;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[0] : send bytes
    // m_lpBuf[0] : send buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::helper_tcp_send( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos::i_socket* lpSocket = lpAioKey->m_pSocket;
        SOCKET hSocket = (SOCKET)lpSocket->get_socket();
        xos_box::i_buf* lpBuf = lpMsg->get_buf( 0, 0 );
        aio_data* lpRetData = 0;

        lpMsg->set_msg( 0, i_aio::AIO_TCP_SEND_RET );
        lpMsg->set_bool( 0, false );
        lpAioKey->m_nPostSendNum++;

        if( 0 == nRet )
        {
            lpRetData = aio_data::get_item_from_pool();
            lpRetData->init();
            lpRetData->m_nType = lpMsg->get_msg( 0, 0 );
            lpRetData->m_lpMsgData = lpMsg;
        }

        if( 0 == nRet )
        {
            WSABUF* lpWsaBuf = lpBuf->get_wsa_buf( 0 );
            lpMsg->set_bool( 0, true );
            lpMsg->set_int( 0, 0 );
            int ret = ::WSASend( hSocket, lpWsaBuf, 1, &lpRetData->m_dwBytes, lpRetData->m_dwFlags, (WSAOVERLAPPED*)&lpRetData->m_ov_ex, 0 );
            if( SOCKET_ERROR == ret )
            {
                DWORD dwErr = WSAGetLastError();
                if( WSA_IO_PENDING != dwErr )
                {
                    nRet = 1;
                }
            }
        }

        if( 0 != nRet )
        {
            lpMsg->set_bool( 0, false );
            PostQueuedCompletionStatus( m_pAioImpl->m_hIocp, 0, 0, (WSAOVERLAPPED*)&lpRetData->m_ov_ex );
        }

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::shut_down_ret( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        // 不会执行到这里，因为shut_down里没有向这post消息
        int nRet = 0;
        return nRet;
    }

    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : how
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::shut_down( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos::i_socket* lpSocket = lpAioKey->m_pSocket;
        int how = lpMsg->get_int( 1, 0 );

        {
            lpMsg->set_msg( 0, i_aio::AIO_TCP_SHUTDOWN_RET );
            lpMsg->set_bool( 0, true );
        }
        {
            lpSocket->shut_down( how );
        }
        {
            m_pAioImpl->notify( lpMsg );
        }

        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::close_net_ret( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        // 不会执行到这里，因为close_net里没有向这post消息
        int nRet = 0;
        return nRet;
    }

    // 
    // m_bData[0] : true or false for opt result
    // 
    // m_nMsg[0]  : cmd type
    // m_nData[1] : linger.l_onoff
    // m_nData[2] : linger.l_linger
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::close_net( int nResult, DWORD dwBytes, aio_key* lpKey, aio_data* lpData )
    {
        int nRet = 0;

        xos_box::i_msg* lpMsg = lpData->m_lpMsgData;
        aio_key* lpAioKey = (aio_key*)lpMsg->get_void( 1, 0 );
        xos::i_socket* lpSocket = lpAioKey->m_pSocket;

        {
            lpMsg->set_msg( 0, i_aio::AIO_TCP_CLOSE_RET );
            lpMsg->set_bool( 0, true );
            lpAioKey->m_eState = aio_key::KEY_STATE_CLOSING;
        }
        {
            CancelIo( (HANDLE)lpSocket->get_socket() );
        }
        // 关闭消息暂存在m_closing_list中，每次处理完消息都判断一下此连接是否已经处理完所有post的请求
        // 如果处理完了，就可以关闭了
        {
            aio_data * p = aio_data::get_item_from_pool();
            p->init();
            p->m_lpMsgData = lpMsg;
            m_pAioImpl->m_closing_list.push_back( p );
            lpMsg = 0;
            p = 0;
        }

        return nRet;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int aio_tcp::post_enough_accept( aio_key * lpAioKey )
    {
        int ret = 0;

        while( ( lpAioKey->m_nPostAcceptNum < mgr::get()->tcp_max_post_accept_num() ) && ( aio_key::KEY_STATE_RUNNING == lpAioKey->m_eState ) )
        {
            helper_post_accept( lpAioKey );
        }

        return ret;
    }

    //
    // 参数pMsg 说明(不同命令会使用其中的不同数据):
    // 
    // m_bData[0] : true or false for opt result
    // m_bData[1] : true or false for server
    // 
    // m_nMsg[0]  : aio cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[0] : send/recv bytes
    // m_lpBuf[0] : send/recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::helper_post_accept( aio_key * lpAioKey )
    {
        int ret = 0;

        xos_box::i_msg * pMsg = 0;
        aio_data::T * pData = 0;

        {
            pMsg = mgr::container()->box()->msg();
            xos_stl::init_pool_item( pData );
        }

        {
            pMsg->set_msg( i_aio::AIO_TCP_ACCPET );
            pMsg->set_void( 0, lpAioKey->m_lpUserKey );
            pMsg->set_void( 1, lpAioKey );
        }

        {
            pData->m_lpMsgData = pMsg;
            pMsg = 0;
            tcp_accept( 0, 0, 0, pData );
            pData->m_lpMsgData = 0;
            xos_stl::term_pool_item( pData );
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int aio_tcp::post_enough_send( aio_key * lpAioKey )
    {
        int ret = 0;

        while( ( lpAioKey->m_nPostSendNum < mgr::get()->tcp_max_post_send_num() ) && ( aio_key::KEY_STATE_RUNNING == lpAioKey->m_eState ) && ( lpAioKey->m_pend_send_list.size() > 0 ) )
        {
            helper_post_send( lpAioKey );
        }

        return ret;
    }

    //
    // 参数pMsg 说明(不同命令会使用其中的不同数据):
    // 
    // m_bData[0] : true or false for opt result
    // m_bData[1] : true or false for server
    // 
    // m_nMsg[0]  : aio cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[0] : send/recv bytes
    // m_lpBuf[0] : send/recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::helper_post_send( aio_key * lpAioKey )
    {
        int ret = 0;

        aio_data::LIST & data_list = lpAioKey->m_pend_send_list;
        aio_data::T * pData = data_list.front();

        if( pData )
        {
            data_list.pop_front();
            helper_tcp_send( 0, 0, 0, pData );
            pData->m_lpMsgData = 0;
            xos_stl::term_pool_item( pData );
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int aio_tcp::post_enough_recv( aio_key * lpAioKey )
    {
        int ret = 0;

        while( ( lpAioKey->m_nPostRecvNum < mgr::get()->tcp_max_post_recv_num() ) && ( aio_key::KEY_STATE_RUNNING == lpAioKey->m_eState ) )
        {
            helper_post_recv( lpAioKey );
        }

        return ret;
    }

    //
    // 参数pMsg 说明(不同命令会使用其中的不同数据):
    // 
    // m_bData[0] : true or false for opt result
    // m_bData[1] : true or false for server
    // 
    // m_nMsg[0]  : aio cmd type
    // 
    // m_nData[1] : local port
    // m_szStr[1] : local ip
    // m_nData[2] : peer port
    // m_szStr[2] : peer ip
    // 
    // m_nData[0] : send/recv bytes
    // m_lpBuf[0] : send/recv buf
    // 
    // m_lpData[0] : UserKey
    // m_lpData[1] : AioKey
    // 
    int aio_tcp::helper_post_recv( aio_key * lpAioKey )
    {
        int ret = 0;

        xos_box::i_buf * pBuf = 0;
        xos_box::i_msg * pMsg = 0;
        aio_data::T * pData = 0;

        {
            pBuf = mgr::container()->box()->buf();
            pMsg = mgr::container()->box()->msg();
            xos_stl::init_pool_item( pData );
        }

        {
            pMsg->set_msg( i_aio::AIO_TCP_RECV );
            pMsg->set_void( 0, lpAioKey->m_lpUserKey );
            pMsg->set_void( 1, lpAioKey );
            pMsg->set_buf( 0, pBuf );
            pMsg->set_int( 0, 0 );
            pBuf = 0;
        }

        {
            pData->m_lpMsgData = pMsg;
            pMsg = 0;
            tcp_recv( 0, 0, 0, pData );
            pData->m_lpMsgData = 0;
            xos_stl::term_pool_item( pData );
        }

        return ret;
    }

} // xos_aio
